﻿using System;
using System.Collections.Generic;
using System.Web.Mvc;

namespace User.Web.Common.WebAttributes
{
    /// <summary>
    /// Eine Attributklasse, die alle wichtigen HTML5 Attribute enthält.
    /// http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html
    /// http://stackoverflow.com/questions/7313284/how-can-editor-templates-display-templates-recognize-any-attributes-assigned-t
    /// http://www.dotnetcurry.com/ShowArticle.aspx?ID=687
    /// Dieses Attribut wird im Model eines ASP.NET MVC Projektes verwendet und erstellt in Verbindung mit den passenden
    /// Editor Templates die passenden HTML5 Attribute für den jeweiligen Controltyp/Datentyp.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class HtmlAttributesAttribute : Attribute, IMetadataAware
    {
        /// <summary>
        /// String der den Key für die "AdditionalValues" Collection enthält in der unsere Attributliste liegt.
        /// </summary>
        public const string HtmlTagAdditionalValuesKey = "HtmlTagAdditionalValues";

        /// <summary>
        /// Wird beim Erstellen der Metadaten für Unser Model aufgerufen und setzt in der passenden Collection
        /// unsere AttributCollection auf die wir dann in den Templates zugreifen können.
        ///  </summary>
        /// <param name="metadata"></param>
        public void OnMetadataCreated(ModelMetadata metadata)
        {
            //metadata.TemplateHint = "Strings";
            metadata.AdditionalValues[HtmlTagAdditionalValuesKey] = OptionalAttributes();
        }

        /// <summary>
        /// Maximale Länge des Eingabefeldes
        /// </summary>
        public int MaxLength { get; set; }

        /// <summary>
        ///  The min and max attributes works with the following input 
        ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
        /// </summary>
        public int Min { get; set; }

        /// <summary>
        /// Gibt an ob ein MinValues angegeben wurde
        /// </summary>
        public bool HasMinValues { get; set; }

        /// <summary>
        ///  The min and max attributes works with the following input
        ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
        /// </summary>
        public int Max { get; set; }

        /// <summary>
        /// The pattern attribute works with the following input types: text, search, url, tel, email, and password.
        /// e.g.: pattern="[A-Za-z]{3}"
        /// </summary>
        public string Pattern { get; set; }

        /// <summary>
        /// The hint is displayed in the input field when it is empty, and disappears when the field gets focus.
        /// </summary>
        public string Placeholder { get; set; }

        /// <summary>
        /// Gibt an ob es sich nur um ein Readonly Feld handelt.
        /// </summary>
        public bool ReadOnly { get; set; }

        /// <summary>
        /// Gibt an ob das Feld Disabled sein soll
        /// </summary>
        public bool Disabled { get; set; }

        /// <summary>
        /// Specifies the shortcut key to activate/focus the element
        /// </summary>
        public string AccessKey { get; set; }

        public int TabIndex { get; set; }
        public string CssClass { get; set; }

        /// <summary>
        /// Gibt an ob auf das Element der Autofokus beim Pageload gesetzt werden soll
        /// Achtung sollte nur einmal Pro "seite" / "Model" verwendet werden.
        /// </summary>
        public bool Autofocus { get; set; }

        /// <summary>
        /// Der Jeweilige Inputtype, hier muss selbst darauf geachtet
        /// werden das dieser nicht mit dem .NET Inputtype "kollidiert"
        ///  und zusammenpasst. - HtmlInputTypes Klasse enthält alle gängigen Input Types
        /// </summary>
        public string InputType { get; set; }

        /// <summary>
        /// Gibt an das das Eingabefeld ausgefüllt sein muss.
        /// </summary>
        public bool Required { get; set; }

        /// <summary>
        /// The step attribute works with the following input types: number, range, date, datetime, datetime-local, month, time and week.
        /// </summary>
        public int Step { get; set; }

        /// <summary>
        /// Rows für Multiline Textbox
        /// </summary>
        public int Rows { get; set; }

        /// <summary>
        /// Erstellt aus den jeweils gesetzten Attributen eine Liste aus Attributname und Value.
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, object> OptionalAttributes()
        {
            var options = new Dictionary<string, object>();

            if (Step != 0)
            {
                options.Add("step", Step);
            }

            if (MaxLength != 0)
            {
                options.Add("maxlength", MaxLength);
            }

            if (ReadOnly)
            {
                options.Add("readonly", "readonly");
            }

            if (Disabled)
            {
                options.Add("disabled", "disabled");
            }
            
            if (Required)
            {
                options.Add("required", "required");
            }

            if (Autofocus)
            {
                options.Add("autofocus", null);
            }

            if (!string.IsNullOrWhiteSpace(AccessKey))
            {
                options.Add("accessKey", AccessKey);
            }

            if (TabIndex != 0)
            {
                options.Add("tabindex", TabIndex);
            }

            if (!string.IsNullOrWhiteSpace(CssClass))
            {
                options.Add("class", CssClass);
            }

            if (Rows > 0)
            {
                options.Add("rows", Rows);
            }

            if (!string.IsNullOrWhiteSpace(InputType))
            {
                //Der Name des Enums entspricht dem Type direkt.
                options.Add("type", InputType);
            }

            if (HasMinValues)
            {
                options.Add("min", Min);
            }

            if (Max > 0)
            {
                options.Add("max", Max);
            }

            if (!string.IsNullOrEmpty(Pattern))
            {
                options.Add("pattern", Pattern);
            }

            if (!string.IsNullOrEmpty(Placeholder))
            {
                options.Add("placeholder", Placeholder);
            }

            return options;
        }
    }
}

